#include <stdio.h>
#include <string.h>
#include "sipsiparser.h"
#include "builderplugin.h"
#include "dvbplugin_chongqing.h"
#include "dvbpluginsipsi_chongqing.h"

#define MAX_ES_PER_PROGRAM	20

static int PluginGetProgElement(builder_section_t* pstPmt, unsigned short u16ServiceId, sipsi_prog_element_t* pstElementArray, unsigned int* pu32EsCnt)
{
	int s32Ret = -1;
	unsigned char* pu8Section;
	unsigned short u16ProgNum;
	unsigned int u32EsCnt;
	unsigned int u32TotalCnt = 0;
	unsigned int i;

	PluginDvbLogcat("PluginGetProgElement() - entry, pstPmt = %p, u16ServiceId = %d, pstElementArray = %p, pu32EsCnt = %p\r\n", pstPmt, u16ServiceId, pstElementArray, pu32EsCnt);
	if(pstPmt && pstElementArray && pu32EsCnt)
	{
		do																			
		{
			pu8Section = pstPmt->m_au8Section;
			u16ProgNum = SiPsiPMTGetServiceID(pu8Section);
			if(u16ServiceId == u16ProgNum)
			{
				u32EsCnt = SiPsiPMTGetElementCount(pu8Section);
				for(i=0;	i<u32EsCnt; i++)
				{
					if(u32TotalCnt < MAX_ES_PER_PROGRAM)
					{
						SiPsiPMTGetElement(pu8Section, &pstElementArray[u32TotalCnt], i);
						u32TotalCnt++;
					}
				}
			}
			pstPmt = pstPmt->m_pstNext;
		}while(pstPmt);
		*pu32EsCnt = u32TotalCnt;
		s32Ret = 0;
	}
	
	PluginDvbLogcat("PluginGetProgElement() - return s32Ret = %d\r\n", s32Ret);
	return s32Ret;

}

int PluginGetProgPids(builder_section_t* pstPmt, unsigned short u16ServiceId, unsigned short * pu16PcrPid, unsigned short* pu16VideoPid, unsigned short* pu16AudioPids, unsigned int* pu32AudioCnt)
{
	int s32Ret = -1;
	unsigned short u16ProgNum;
	unsigned int u32EsCnt;
	unsigned int i;
	sipsi_prog_element_t stElement;
	unsigned int u32AudioCnt = 0;

	PluginDvbLogcat("PluginGetProgPids() - entry, pstPmt = %p, u16ServiceId = %d, pcrPID = %p, vID = %p, aIDs = %p, pu32AudioCnt = %p\r\n", pstPmt, u16ServiceId, pu16PcrPid, pu16VideoPid, pu16AudioPids, pu32AudioCnt);
	while(pstPmt)					
	{
		u16ProgNum = SiPsiPMTGetServiceID(pstPmt->m_au8Section);
		if(u16ProgNum == u16ServiceId)
		{
			s32Ret = 0;
			u32EsCnt = SiPsiPMTGetElementCount(pstPmt->m_au8Section);
			for(i=0; i<u32EsCnt; i++)
			{
				SiPsiPMTGetElement(pstPmt->m_au8Section, &stElement, i);
				switch(stElement.m_u8StreamType)
				{
					case SIPSI_ES_TYPE_MPEG1_VIDEO:
					case SIPSI_ES_TYPE_MPEG2_VIDEO:
					case SIPSI_ES_TYPE_MPEG4_VIDEO:
					case SIPSI_ES_TYPE_VIDEO_HEVC:
					case SIPSI_ES_TYPE_VIDEO_CAVS:
						if (pu16VideoPid)
							*pu16VideoPid = stElement.m_u16ElementaryPid;
						break;
					case SIPSI_ES_TYPE_MPEG1_AUDIO:
					case SIPSI_ES_TYPE_MPEG2_AUDIO:
					case SIPSI_ES_TYPE_AAC:
					case SIPSI_ES_TYPE_AAC1:
					case SIPSI_ATSC_DOLBY_DIGITAL:
					case SIPSI_ES_TYPE_DTS_AUDIO:
						if (pu16AudioPids)
							pu16AudioPids[u32AudioCnt++] = stElement.m_u16ElementaryPid;
						break;
					case SIPSI_ES_TYPE_PRIVATE_PES:
						if(SiPsiFindDescriptor(stElement.m_pu8Descriptors, stElement.m_u16EsInfoLength, SIPSI_DESCTAG_AC3))
						{
							if (pu16AudioPids)
								pu16AudioPids[u32AudioCnt++] = stElement.m_u16ElementaryPid;
						}
						break;
					default:
						break;
				}
			}
			if(pu16PcrPid)
				*pu16PcrPid = SiPsiPMTGetPCRPID(pstPmt->m_au8Section); 
			*pu32AudioCnt = u32AudioCnt;
		}
		pstPmt = pstPmt->m_pstNext;
	}
	PluginDvbLogcat("PluginGetProgPids() - return s32Ret = %d\r\n", s32Ret);
	return s32Ret;
}

static int PluginServiceNameCheck(sipsi_dvbservice_t* pstService)
{
	int s32Ret = -1;
	char as8ServiceName[100] = {0};
	char as8ProviderName[100]={0};
	char as8Lan[4] = {0};
	unsigned short u16ServiceNameLen;
	unsigned short u16ProviderNameLen;

	SiPsiSDTGetServiceName(pstService, as8ProviderName, &u16ProviderNameLen, as8ServiceName, &u16ServiceNameLen, as8Lan);
	//if(as8ServiceName[0]!=0x0 && ((as8ServiceName[0]>='0' && as8ServiceName[0]<='9')||(as8ServiceName[0]>='A' && as8ServiceName[0]<='Z')||(as8ServiceName[0]>='a' && as8ServiceName[0]<='z')||(as8ServiceName[0]>0x7f)))
	//	s32Ret = 0;
	if(as8ServiceName[0] == 0x11)//unicode
	{
		unsigned short u16Unicode;

		u16Unicode = (as8ServiceName[1]<<8)|as8ServiceName[2];
		if(u16Unicode!=0x0 && ((u16Unicode>='0' && u16Unicode<='9')||(u16Unicode>='A' && u16Unicode<='Z')||(u16Unicode>='a' && u16Unicode<='z')||(u16Unicode>0x7f)))
			s32Ret = 0;
	}
	else if(as8ServiceName[0] == 0x13)//gb2312
	{
		if(as8ServiceName[1]!=0x0 && ((as8ServiceName[1]>='0' && as8ServiceName[1]<='9')||(as8ServiceName[1]>='A' && as8ServiceName[1]<='Z')||(as8ServiceName[1]>='a' && as8ServiceName[1]<='z')))
			s32Ret = 0;
		else if(as8ServiceName[1]!=0xA3 && as8ServiceName[2]!=0xBF)
			s32Ret = 0;
	}
	else if(as8ServiceName[0] > 0x20)
	{	
		if(as8ServiceName[0]!=0x0 && ((as8ServiceName[0]>='0' && as8ServiceName[0]<='9')||(as8ServiceName[0]>='A' && as8ServiceName[0]<='Z')||(as8ServiceName[0]>='a' && as8ServiceName[0]<='z')||(as8ServiceName[0]>0x7f)))
			s32Ret = 0;
	}
	else
	{
		PluginDvbLogcat("PluginServiceNameCheck() - unknown type as8ServiceName[0] = %d\r\n", as8ServiceName[0]);	
	}
	
	return s32Ret;
}

static int PluginNoServiceDescServiceGetType(builder_ts_t *pstTs, sipsi_dvbservice_t* pstService, unsigned char* pu8ServiceType)
{
	int s32Ret = -1;
	unsigned char* pu8Des;
	unsigned short u16PmtPid;
	sipsi_prog_element_t stEsInfo[MAX_ES_PER_PROGRAM];
	unsigned int u32EsCnt;
	unsigned int i;

	PluginDvbLogcat("PluginNoServiceDescServiceGetType() - entry, pstTs = %p, pstService = %p, pu8ServiceType = %p\r\n", pstTs, pstService, pu8ServiceType);	
	pu8Des = SiPsiFindDescriptor(pstService->m_pu8Descriptors, pstService->m_u16DescriptorLoopLength, SIPSI_DESCTAG_DATA_BROADCAST_MDESCRIPTOR);
	if (pu8Des != NULL)
	{
		*pu8ServiceType = SIPSI_SERVICE_TYPE_DATA;
	}
	else
	{
		u16PmtPid = SiPsiPATGetPmtPID(pstTs->m_stSiPsi.m_pstPat->m_au8Section, pstService->m_u16ServiceId);
		if(u16PmtPid > 0)
		{
			u32EsCnt = 0;
			*pu8ServiceType = -1;
			s32Ret = PluginGetProgElement(pstTs->m_stSiPsi.m_pstPmt, pstService->m_u16ServiceId, stEsInfo, &u32EsCnt);
			for (i=0; i<u32EsCnt; i++)
			{
				switch(stEsInfo[i].m_u8StreamType)
				{
					case SIPSI_ES_TYPE_MPEG1_VIDEO:		
					case SIPSI_ES_TYPE_MPEG2_VIDEO:
					case SIPSI_ES_TYPE_MPEG4_VIDEO:
					case SIPSI_ES_TYPE_VIDEO_HEVC:
					case SIPSI_ES_TYPE_VIDEO_CAVS:
						*pu8ServiceType = SIPSI_SERVICE_TYPE_VIDEO;
					break;
					case SIPSI_ES_TYPE_MPEG1_AUDIO:
					case SIPSI_ES_TYPE_MPEG2_AUDIO:
					case SIPSI_ES_TYPE_AAC:
					case SIPSI_ES_TYPE_AAC1:
					case SIPSI_ATSC_DOLBY_DIGITAL:
					case SIPSI_ES_TYPE_DTS_AUDIO:
					{
						if(*pu8ServiceType == -1)
							*pu8ServiceType = SIPSI_SERVICE_TYPE_AUDIO;
						break;
					}
					case 0x0B:
						*pu8ServiceType = SIPSI_SERVICE_TYPE_DATA;
						break;
				}
			}
		}	
		else
		{
			PluginDvbLogcat("PluginNoServiceDescServiceGetType() - found sdt no pmt pstService->m_u16ServiceId =%d\r\n", pstService->m_u16ServiceId);
		}
	}

	PluginDvbLogcat("PluginNoServiceDescServiceGetType() - return s32Ret = %d\r\n", s32Ret);
	return s32Ret;
}

static int PluginServiceTypeCheck(builder_ts_t *pstTs, sipsi_dvbservice_t* pstService, unsigned char u8ServiceType)
{
	int s32Ret = -1;	
	unsigned short u16PmtPid;
	builder_section_t* pstSectionList = NULL;
	unsigned short u16PcrPid;
	unsigned short u16VideoPid;
	unsigned short au16AudioPid[16];
	unsigned int u32AudioCnt;
	
	PluginDvbLogcat("PluginServiceTypeCheck() - entry, pstTs = %p, pstService = %p, u8ServiceType = %d\r\n", pstTs, pstService, u8ServiceType);
	if ((u8ServiceType==SIPSI_SERVICE_TYPE_VIDEO) || (u8ServiceType==SIPSI_SERVICE_TYPE_AUDIO))
	{
		u16PmtPid = SiPsiPATGetPmtPID(pstTs->m_stSiPsi.m_pstPat->m_au8Section, pstService->m_u16ServiceId);
		if  (u16PmtPid > 0)
		{
			PluginDvbLogcat("PluginServiceTypeCheck() - u16PmtPid = %d, pstService->m_u16ServiceId = %d\r\n", u16PmtPid, pstService->m_u16ServiceId);
			pstSectionList = pstTs->m_stSiPsi.m_pstPmt;
			while(pstSectionList)
			{
				PluginDvbLogcat("PluginServiceTypeCheck() - PMT list service id = %d\r\n", SiPsiPMTGetServiceID(pstSectionList->m_au8Section));
				if(SiPsiPMTGetServiceID(pstSectionList->m_au8Section) == pstService->m_u16ServiceId)
				{
					if (u8ServiceType==SIPSI_SERVICE_TYPE_VIDEO || u8ServiceType==SIPSI_SERVICE_TYPE_AUDIO)
					{
						u32AudioCnt = 0;
						PluginGetProgPids(pstTs->m_stSiPsi.m_pstPmt, pstService->m_u16ServiceId, &u16PcrPid, &u16VideoPid, au16AudioPid, &u32AudioCnt);	
						if (u16PcrPid==0x1fff && u8ServiceType==SIPSI_SERVICE_TYPE_VIDEO)
						{
							PluginDvbLogcat("PluginServiceTypeCheck() - error, stService.service_id = %d PCRPID=0x1fff\r\n", pstService->m_u16ServiceId);
							//s32Ret = -1;
							//break;
						}
						if (u8ServiceType==SIPSI_SERVICE_TYPE_VIDEO && u16VideoPid==0x1fff)
						{
							PluginDvbLogcat("PluginServiceTypeCheck() - error, stService.service_id = %d u16VideoPid=0x%x\r\n", pstService->m_u16ServiceId, u16VideoPid);
							s32Ret = -1;
							break;	
						}
						s32Ret = 0;
					}
					break;
				}
				pstSectionList = pstSectionList->m_pstNext;
			}
			if (pstSectionList == NULL)
			{
				PluginDvbLogcat("PluginServiceTypeCheck() - SericeID=%d has no PMT\r\n", pstService->m_u16ServiceId);
				s32Ret = -1;
			}	
		}
		else
		{
			PluginDvbLogcat("PluginServiceTypeCheck() - SericeID=%d PAT has no this program_number\r\n", pstService->m_u16ServiceId);
			s32Ret = -1;
		}	
	}
	else
	{
		PluginDvbLogcat("PluginCheckService() - unsupport TV or RADIO type check\r\n");
		s32Ret = -1;
	}
	PluginDvbLogcat("PluginCheckService() - return s32Ret = %d\r\n", s32Ret);
	return s32Ret;
}

unsigned char PluginTransformType(unsigned char u8MpegTye)
{
	unsigned char u8PluginType = BUILDER_SERVICE_UNKNOWN;
	
	PluginDvbLogcat("PluginTransformType() - entry, u8MpegTye = %d\r\n", u8MpegTye);
	switch(u8MpegTye)
	{
		case SIPSI_SERVICE_TYPE_VIDEO:
			u8PluginType = BUILDER_SERVICE_SDTV;
			break;
		case SIPSI_SERVICE_TYPE_AUDIO:
			u8PluginType = BUILDER_SERVICE_RADIO;
			break;
	}
	PluginDvbLogcat("PluginTransformType() - return u8PluginType = %d\r\n", u8PluginType);
	return u8PluginType;	
}

int PluginParseTs(builder_ts_t *pstTs, builder_service_t* pstServices, unsigned int* pu32ServiceCnt)
{
	int s32Ret = 0;
	unsigned int u32Cnt = 0;
	int u32SdtProgCnt;
	unsigned char* pu8Des;
	unsigned int i;
	sipsi_dvbservice_t stService;
	unsigned char u8ServiceType;
	char as8ServiceName[100];
	char as8ProviderName[100];
	unsigned short u16ServiceNameLen;
	unsigned short u16ProviderNameLen;	
	unsigned char* pu8Section;
	unsigned short u16NetworkId;
	unsigned short u16TransportId;
	unsigned short u16PcrPid;
	unsigned short u16VideoPid;
	unsigned short au16AudioPid[16];
	unsigned int u32AudioCnt;
	builder_section_t* pstSectionList = NULL;
	char as8Lan[4] = {0};

	PluginDvbLogcat("PluginParseTs() - entry, pstTs = %p, pProgInfo = %p, pu32ProgCnt = %p\r\n", pstTs, pstServices, pu32ServiceCnt);
	if(pstTs && pstServices && pu32ServiceCnt)
	{
		if(pstTs->m_stSiPsi.m_pstSdt)
		{
			pstSectionList = pstTs->m_stSiPsi.m_pstSdt;
			while(pstSectionList)
			{
				pu8Section = pstSectionList->m_au8Section;			
				u32SdtProgCnt = SiPsiSDTGetServiceCount(pu8Section);
				u16NetworkId = SiPsiSDTGetNetID(pu8Section);
				u16TransportId = SiPsiPATGetStreamID(pstTs->m_stSiPsi.m_pstPat->m_au8Section);

				pstTs->m_u16NetId = u16NetworkId;
				pstTs->m_u16TsId = u16TransportId;
				PluginDvbLogcat("PluginParseTs() - serviceCount=%d\r\n", u32SdtProgCnt);
				for(i=0; i<u32SdtProgCnt; i++)
				{
					SiPsiSDTGetService(pu8Section, &stService, i);
					pu8Des = SiPsiFindDescriptor(stService.m_pu8Descriptors, stService.m_u16DescriptorLoopLength, SIPSI_DESCTAG_SERVICE);
					if(pu8Des == NULL)
					{
						PluginDvbLogcat("PluginParseTs() - found service has no SIPSI_DESCTAG_SERVICE, stService.m_u16ServiceId = %, pstTs->m_stTuner.m_u32Freq = %d\r\n", stService.m_u16ServiceId, pstTs->m_stTuner.m_u32Freq);
						s32Ret = PluginNoServiceDescServiceGetType(pstTs, &stService, &u8ServiceType);
						if(s32Ret == -1)
						{
							PluginDvbLogcat("PluginParseTs() - no service descriptor get service type error, stService.service_id = %d\r\n", stService.m_u16ServiceId);
						}
					}
					else
					{
						u8ServiceType = pu8Des[2];												
					}

					if(u8ServiceType ==SIPSI_SERVICE_TYPE_ADVANCE_SDTV || u8ServiceType ==SIPSI_SERVICE_TYPE_ADVANCE_HDTV)
					{
						u8ServiceType = SIPSI_SERVICE_TYPE_VIDEO;
					}
					
					if(PluginServiceTypeCheck(pstTs, &stService, u8ServiceType) != 0)
						continue;
					
					if(PluginServiceNameCheck(&stService) != 0)
						continue;

					SiPsiSDTGetServiceName(&stService, as8ProviderName, &u16ProviderNameLen, as8ServiceName, &u16ServiceNameLen, as8Lan);
					PluginDvbLogcat("PluginParseTs() - SiPsiSDTGetServiceName as8ServiceName[0] = %d, u16ServiceNameLen = %d, u16NetworkId = %d, u16TransportId = %d\r\n", as8ServiceName[0], u16ServiceNameLen, u16NetworkId, u16TransportId);
					memcpy(pstServices[u32Cnt].m_as8Name, as8ServiceName, sizeof(pstServices[u32Cnt].m_as8Name));
					pstServices[u32Cnt].m_as8Name[sizeof(pstServices[u32Cnt].m_as8Name)-1] = 0;
					pstServices[u32Cnt].m_u16NameLen = u16ServiceNameLen;
					pstServices[u32Cnt].m_eType = PluginTransformType(u8ServiceType);					
					pstServices[u32Cnt].m_u16Serviceid = stService.m_u16ServiceId;
					pstServices[u32Cnt].m_u16Lcn = 0;
					pstServices[u32Cnt].m_u16Orgnetid = u16NetworkId;
					pstServices[u32Cnt].m_u16Tsid = u16TransportId;
					pstServices[u32Cnt].m_u32Freq = pstTs->m_stTuner.m_u32Freq;
					u32Cnt++;				
				}
				pstSectionList = pstSectionList->m_pstNext;
			}
		}
		else if(pstTs->m_stSiPsi.m_pstPat && pstTs->m_stSiPsi.m_pstPmt)
		{
			PluginDvbLogcat("PluginParseTs() - found sdt null\r\n");
			pstSectionList = pstTs->m_stSiPsi.m_pstPmt;
			u16TransportId = SiPsiPATGetStreamID(pstTs->m_stSiPsi.m_pstPat->m_au8Section);
			pstTs->m_u16NetId = 1;
			pstTs->m_u16TsId = u16TransportId;
			while(pstSectionList)
			{
				u32AudioCnt = 0;
				stService.m_u16ServiceId = SiPsiPMTGetServiceID(pstSectionList->m_au8Section);
				PluginGetProgPids(pstSectionList, stService.m_u16ServiceId, &u16PcrPid, &u16VideoPid, au16AudioPid, &u32AudioCnt);
				if (u16VideoPid != 0x1fff)
				{
					u8ServiceType = SIPSI_SERVICE_TYPE_VIDEO;
				}
				else if (au16AudioPid[0] != 0x1fff)
				{
					u8ServiceType = SIPSI_SERVICE_TYPE_AUDIO;
				}	
				memset(pstServices[u32Cnt].m_as8Name, 0, sizeof(pstServices[u32Cnt].m_as8Name));
				sprintf(pstServices[u32Cnt].m_as8Name, "unknown name%d", stService.m_u16ServiceId);
				pstServices[u32Cnt].m_u16NameLen = strlen(pstServices[u32Cnt].m_as8Name);
				pstServices[u32Cnt].m_eType = PluginTransformType(u8ServiceType);					
				pstServices[u32Cnt].m_u16Serviceid = stService.m_u16ServiceId;
				pstServices[u32Cnt].m_u16Lcn = 0;
				pstServices[u32Cnt].m_u16Orgnetid = 1;
				pstServices[u32Cnt].m_u16Tsid = u16TransportId;
				pstServices[u32Cnt].m_u32Freq = pstTs->m_stTuner.m_u32Freq;
				u32Cnt++;
				pstSectionList = pstSectionList->m_pstNext;
			}
		}
		else
		{
			s32Ret = -1;
			PluginDvbLogcat("PluginParseTs() - pstTs content error, pstTs->m_stTuner.m_u32Freq = %d\r\n", pstTs->m_stTuner.m_u32Freq);
		}
	}
	*pu32ServiceCnt = u32Cnt;
	PluginDvbLogcat("PluginParseTs() - return u32Cnt = %d s32Ret = %d\r\n", u32Cnt, s32Ret);
	return s32Ret;
}

